/*
 * Copyright (c) 2022-2023 Termony Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ASSEMBLY
#define ASSEMBLY 1
#endif

#include "los_arch_assembler.h"
#include "los_arch_marcos.h"

FILE_BEGIN()

    EXPORT_LABEL(_vector_table)

    IMPORT_LABEL(g_exc)
    IMPORT_LABEL(_boot)
    IMPORT_LABEL(HalInterrupt)
    IMPORT_LABEL(HalExcHandleEntry)
    IMPORT_LABEL(HalTaskSwitch)
    IMPORT_LABEL(HalTaskSwitchFromISR)


MACRO_DEF(VENTERY label)
    .balign 128
    b   \label
MACRO_END()

    SECTION(.vectors)

    .balign 2048
FUNC_DEF(_vector_table)
    /* Exception from CurrentEL (EL1t) with SP_EL0 (SPSEL = 0) */
    VENTERY(HalSyncExceptHdl)   /* Synchronous */
    VENTERY(HalIrqInterruptHdl) /* IRQ/vIRQ */
    VENTERY(HalFiqInterruptHdl) /* FIQ/vFIQ */
    VENTERY(HalSErrorExceptHdl) /* SError/vSError */
    /* Exception from CurrentEL (EL1h) with SP_ELn */
    VENTERY(HalSyncExceptHdl)   /* Synchronous */
    VENTERY(HalIrqInterruptHdl) /* IRQ/vIRQ */
    VENTERY(HalFiqInterruptHdl) /* FIQ/vFIQ */
    VENTERY(HalSErrorExceptHdl) /* SError/vSError */
    /* Exception from lower EL, aarch64 */
    VENTERY(HalSyncExceptHdl)   /* Synchronous */
    VENTERY(HalIrqInterruptHdl) /* IRQ/vIRQ */
    VENTERY(HalFiqInterruptHdl) /* FIQ/vFIQ */
    VENTERY(HalSErrorExceptHdl) /* SError/vSError */
    /* Exception from lower EL, aarch32 */
    VENTERY(HalSyncExceptHdl)   /* Synchronous */
    VENTERY(HalIrqInterruptHdl) /* IRQ/vIRQ */
    VENTERY(HalFiqInterruptHdl) /* FIQ/vFIQ */
    VENTERY(HalSErrorExceptHdl) /* SError/vSError */
    FUNC_END()


    SECTION(.text)

/* 保存异常上下文. */
MACRO_DEF(SAVE_EXC_CONTEXT)
    /* 保存通用寄存器X0 ~ X30和SP. */
    PUSH_REG_ALL_COMMON SP
    /* 获取寄存器ELR和SPSR并保存. */
    GET_REG_ELR_SPSR X0 X2 X3
    STP     X2, X3, [SP, #-0x10]!
    /* 判断异常前的栈指针(SP_EL0t, SP_ELxt或SP_ELxh). */
    AND     X5, X3, #1
    CMP     X5, #1
    BEQ     1f
    /* 获取任务栈指针(SP_EL0). */
    MSR     SPSEL, #0
    MOV     X4, SP
    MSR     SPSEL, #1
    B       2f
1:
    /* 获取异常栈指针(SP_EL1). */
    ADD     X4, SP, #(34 * 8)
2:
    /* 保存异常前的栈指针(SP). */
    STR     X4, [SP, #(3 * 8)]
MACRO_END()


/* 恢复异常上下文. */
MACRO_DEF(RESTORE_EXC_CONTEXT)
    /* 恢复寄存器ELR和SPSR并设置. */
    LDP     X2, X3, [SP], #0x10
    SET_REG_ELR_SPSR X0 X2 X3
    /* 恢复通用寄存器X0 ~ X30. */
    POP_REG_ALL_COMMON SP
MACRO_END()


FUNC_DEF(HalSyncExceptHdl)
    /* 保存异常上下文. */
    SAVE_EXC_CONTEXT

    /* 获取ESR和FAR寄存器. */
    GET_REG_ESR_FAR X0 X2 X3
    /* 判断异常类型并调用相应处理程序. */
    LSR     X1, X2, #26
    CMP     X1, #0x15   /* 0x15 = SVC指令. */
    BEQ     TASK_SWITCH
    CMP     X1, #0x16   /* 0x16 = HVC指令. */
    BEQ     TASK_SWITCH
    CMP     X1, #0x17   /* 0x17 = SMC指令. */
    BEQ     TASK_SWITCH

    /* 获取当前栈指针(SP). */
    MOV     X1, SP

    /* 跳转到异常处理函数. */
    BL      HalExcHandleEntry

    /* 恢复异常上下文. */
    RESTORE_EXC_CONTEXT
    ERET

TASK_SWITCH:
    /* 恢复异常上下文. */
    RESTORE_EXC_CONTEXT
    /* 切换任务上下文. */
    B       HalTaskSwitch
    FUNC_END()


FUNC_DEF(HalSErrorExceptHdl)
    /* 保存异常上下文. */
    SAVE_EXC_CONTEXT

    /* 获取ESR和FAR寄存器. */
    GET_REG_ESR_FAR X0 X2 X3

    /* 获取当前栈指针(SP). */
    MOV     X1, SP

    /* 跳转到异常处理函数. */
    BL      HalExcHandleEntry

    /* 恢复异常上下文. */
    RESTORE_EXC_CONTEXT
    ERET
    FUNC_END()


/* 保存中断上下文. */
MACRO_DEF(SAVE_INT_CONTEXT)
    /* 保存通用寄存器X0 ~ X19, X29和X30. */
    PUSH_REG_PART_COMMON SP
    /* 获取寄存器ELR和SPSR并保存. */
    GET_REG_ELR_SPSR X0 X2 X3
    STP     X2, X3, [SP, #-0x10]!
MACRO_END()


/* 恢复中断上下文. */
MACRO_DEF(RESTORE_INT_CONTEXT SP)
    /* 恢复寄存器ELR和SPSR并设置. */
    LDP     X2, X3, [SP], #0x10
    SET_REG_ELR_SPSR X0 X2 X3
    /* 恢复通用寄存器X0 ~ X19, X29和X30. */
    POP_REG_PART_COMMON SP
MACRO_END()


FUNC_DEF(HalIrqInterruptHdl)
    /* 保存中断上下文. */
    SAVE_INT_CONTEXT

    /* 读取ICC_IAR的值到X0中. */
    MRS     X0, S3_0_C12_C12_0
    /* 将ICC_IAR的值保存到栈中. */
    STR     X0, [SP, #-0x8]!

    /* 调用应用层中断处理程序, 通过X0传递中断号. */
    BL      HalInterrupt

    /* 从栈中恢复ICC_IAR的值到X0. */
    LDR     X0, [SP], #0x8
    /* 将X0写入ICC_EOIR来结束中断处理. */
    MSR     S3_0_C12_C12_1, X0

    /* 恢复中断上下文. */
    RESTORE_INT_CONTEXT
    /* 在中断中切换任务上下文. */
    B       HalTaskSwitchFromISR
    FUNC_END()


FUNC_DEF(HalFiqInterruptHdl)
    /* 保存中断上下文. */
    SAVE_INT_CONTEXT

    /* 读取ICC_IAR的值到X0中. */
    MRS     X0, S3_0_C12_C12_0
    /* 将ICC_IAR的值保存到栈中. */
    STR     X0, [SP, #-0x8]!

    /* 调用应用层中断处理程序, 通过X0传递中断号. */
    BL      HalInterrupt

    /* 从栈中恢复ICC_IAR的值到X0. */
    LDR     X0, [SP], #0x8
    /* 将X0写入ICC_EOIR来结束中断处理. */
    MSR     S3_0_C12_C12_1, X0

    /* 恢复中断上下文. */
    RESTORE_INT_CONTEXT
    ERET
    FUNC_END()

FILE_END()